package com.kk.xhr.util;

import org.apache.commons.lang3.tuple.Pair;
import org.springframework.lang.Nullable;

import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;

/**
 * DATE UTIL
 *
 * @author luokexiong
 * @version 1.0 2021/2/14 11:16 上午
 * @since 1.0.0
 */
public final class DateUtil {

    public static final long PRE_SECOND_MILLS = 1000;
    /** 默认上海 */
    private static final ZoneId ZONE_ID = ZoneId.of("Asia/Shanghai");
    /** mysql 时间日期格式 */
    public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 将{@code localDateTime}转换成milli timestamp
     *
     * @param localDateTime localDateTime
     * @return 毫秒级时间戳
     */
    public static long toMilliTimeStamp(LocalDateTime localDateTime) {
        return localDateTime.atZone(ZONE_ID).toInstant().toEpochMilli();
    }

    /**
     * 将{@code localDateTime}转换成milli timestamp
     *
     * @param localDateTime 为空时返回当前时间戳
     * @return 毫秒级时间戳
     */
    public static long toMilliTimeStampOrNow(@Nullable LocalDateTime localDateTime) {
        if (null == localDateTime) {
            return toMilliTimeStamp(now());
        }
        return toMilliTimeStamp(localDateTime);
    }

    private DateUtil() {
    }

    public static LocalDateTime from(Long ts) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(ts), ZONE_ID);
    }

    /**
     * 当前时间
     *
     * @return local date time
     */
    public static LocalDateTime now() {
        return LocalDateTime.now(ZONE_ID);
    }

    /**
     * 当前秒级时间戳
     *
     * @param localDateTime local date time
     * @return seconds timestamp
     */
    public static long toSecondsTimeStamp(LocalDateTime localDateTime) {
        return localDateTime.atZone(ZONE_ID).toEpochSecond();
    }

    /**
     * 获取当天0时的时刻
     *
     * @return {@linkplain LocalDateTime localDateTime}
     */
    public static LocalDateTime currentDayZeroClock() {
        return LocalDateTime.of(LocalDate.now(ZONE_ID), LocalTime.MIN);
    }

    /**
     * 获取当天剩余的秒数
     *
     * @return {@linkplain LocalDateTime localDateTime}
     */
    public static long currentDayRemainSeconds() {
        return LocalTime.MAX.toSecondOfDay() - LocalTime.now(ZONE_ID).toSecondOfDay();
    }

    /**
     * 获取当前日期(仅包含年月日)的字符串形式
     *
     * @return current date string
     */
    public static String getTodayDateYYYYMMDD() {
        LocalDate now = LocalDate.now();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        return now.format(dateTimeFormatter);
    }

    /**
     * 获取时间的字符串形式
     *
     * @param dateTime date time
     * @return date time string
     */
    public static String dateToString(LocalDateTime dateTime) {
        if (null == dateTime) {
            return "";
        }
        return dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
    }

    /**
     * 获取升序最新的order字段。用于素材分组，和素材分组里的素材的排序。
     *
     * @return newest order
     */
    public static int newestAscFirst() {
        return -(int) Instant.now().getEpochSecond();
    }

    /**
     * 获取今天结束时的时间戳
     *
     * @return 时间戳，毫秒
     */
    public static long getEndOfTodayMillis() {
        return toMilliTimeStamp(LocalDateTime.of(now().toLocalDate(), LocalTime.MAX));
    }

    /**
     * 时间校验
     *
     * @param timestamp 时间戳
     * @return 时间
     */
    public static LocalDateTime validTime(Long timestamp) {
        if (null == timestamp) {
            return null;
        }
        return DateUtil.from(timestamp);
    }

    /**
     * 获取上一周的周一和周日
     *
     * @return 上一周的周一和周日
     */
    public static Pair<LocalDateTime, LocalDateTime> getWeek() {
        LocalDate now = LocalDate.now();
        // 求这个日期上一周的周一、周日
        LocalDate todayOfLastWeek = now.minusDays(7);
        LocalDate monday = todayOfLastWeek.with(TemporalAdjusters.previous(DayOfWeek.SUNDAY)).plusDays(1);
        LocalDate sunday = todayOfLastWeek.with(TemporalAdjusters.next(DayOfWeek.MONDAY)).minusDays(1);
        return Pair.of(LocalDateTime.of(monday, LocalTime.MIN), LocalDateTime.of(sunday, LocalTime.MIN));
    }

    /**
     * 获取上个月第一天和最后一天
     *
     * @return 上个月的第一天和最后一天
     */
    public static Pair<LocalDateTime, LocalDateTime> getMouth() {
        LocalDate date = LocalDate.now().minusMonths(1L);
        LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth());
        LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth());
        return Pair.of(LocalDateTime.of(firstDay, LocalTime.MIN), LocalDateTime.of(lastDay, LocalTime.MAX));
    }
}
